#pragma once

#include <atomic>

#include "TxnnCpp/Common.h"

namespace common {

/**
 * ISpinLock
 */
class ISpinLock {
public:
  ROOT_INTERFACE_PROTECTED_DTOR(ISpinLock);

  virtual void lock() _TX_NOEXCEPT = 0;
  virtual void unlock() _TX_NOEXCEPT = 0;

protected:
  std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
};

/*
 * SpinLock
 */
class SpinLock _TX_FINAL : public ISpinLock {
public:
  void lock() _TX_NOEXCEPT _TX_OVERRIDE {
    while (lock_.test_and_set()) {
      /* code blank */
    }
  }

  void unlock() _TX_NOEXCEPT _TX_FINAL { lock_.clear(); }
};

/*
 * SpinLockGuard
 */
class SpinLockGuard _TX_FINAL : private NonCopyable {
public:
  explicit SpinLockGuard(ISpinLock& lock) : lock_(lock) { lock_.lock(); }
  ~SpinLockGuard() { lock_.unlock(); }

private:
  ISpinLock& lock_;
};

} // namespace common